$MOD186
$EP
NAME TIMER
; Main program for uPD70208 microcomputer system
;
; Author: 	Dr Tay Teng Tiow
; Address:     	Department of Electrical Engineering 
;         	National University of Singapore
;		10, Kent Ridge Crescent
;		Singapore 0511.	
; Date:   	6th September 1991
;
; This file contains proprietory information and cannot be copied 
; or distributed without prior permission from the author.
; =========================================================================

public	serial_rec_action, timer2_action, timer1_action
extrn	print_char:far, print_2hex:far, iodefine:far
extrn   set_timers:far

STACK_SEG	SEGMENT
		DB	256 DUP(?)
	TOS	LABEL	WORD
STACK_SEG	ENDS

DATA_SEG	SEGMENT
;ASCII 10: go to next line, ; \n
;ASCII 13: move to the start of the line \r
	T_COUNT		DB	0FH
	T_COUNT_SET	DB	0FH
	REC_MESS	DB	10,13,'Period of timer0 =     '
	COUNTER 	DB  00H ; whole process counter (for debugging)


;keypad LUT
	leftKeyMap  db  1, 2, 3, 4, 5, 6, 7, 8, 9,10, 0,11
	rightKeyMap db 12,13,14,15,16,17,18,19,20,21,22,23

;7 seg LUT:
;10 del(-)			, 11 enter(_|)
;12 Start Trans (|_), 13 Cancel Tran (=), 14 End Trans (_|), 
;15 add Item (o)B4	, 16 Quantity (.)40h, 17 Remove item (R)3F
;18 Disp Total(=_)90, 19 Current Amount(C)87h
;23 RESET (|_|)
	PATTERN_E 	EQU 25
	PATTERN_P 	EQU 26
	PATTERN_EQU EQU 27
	PATTERN_SPACE EQU 28
;index:				0     1     2     3     4     5     6     7     8     9     10    11
	SegPattern	db	0AFh, 028h, 09Dh, 0B9h, 03Ah, 0B3h, 0B7h, 029h, 0BFh, 0BBh, 010h, 0A0h
;					12    13    14    15    16    17    18    19    20    21    22    23
				db  086h, 011h, 0A8h, 0B4h, 040h, 03Fh ,090h ,087h ,0    ,0    ,0    ,0
;					24(F) 25(E) 26(P) 27(=) 28( )
				db  017h, 097h, 01fh, 090h, 0
	SegNum		db	10,10,10,10,10,10
	SegPosition	db	0BFh, 0DFh, 0EFh, 0F7h, 0FBh, 0FDh

	SegCounter  db 0
	Display_isNumber db 0

	T0_top 	db 10
	T0 		DB 0

;T1_top: t1 top counter, T1: intial value of counter 
;reduce the timer at MISC.ASM 
;change to word if the value of top counter is more than 256
; 3ms => 333.3Hz, each display at 333/6 = 55.5Hz
; 33*3=99ms => ~10Hz
; 66*3=198ms => ~5Hz

	T1_top 		db 	33	
	T1 			db 	00h
	T1_prev		db  00h
	
	T2_top		dw 	66 	
;	T2_top		dw  330
	T2 			dw 	01H
	T2_prev 	db  00h

	KEY_PREV	DB  0FFH

;initialize of the queue 
	KEY_QUEUE_LEN	EQU	32 ; length of the queue
	KEY_QUEUE_TRANS	DB	KEY_QUEUE_LEN DUP(?) ; reserve a space for the queue
	KEY_QUEUE_HEAD	DW	0H ; head of queue - READ FROM HEAD
	KEY_QUEUE_TAIL	DW	0H ; tail of queue - WRITE TO TAIL
	KEY_QUEUE_READY DB  0

;PACKAGE SENDING
	PACKAGE_TAIL 	DB 0
	PACKAGE_HEAD	DB 0
	PACKAGE_ARR 	DB 32 dup(?)

;SERIAL QUEUE RECEIVED FROM SHOP PC
	SERIAL_QUEUE_LEN	EQU	64 ; length of the queue
	SERIAL_QUEUE_TRANS	DB	SERIAL_QUEUE_LEN DUP(?) ; reserve a space for the queue
	SERIAL_QUEUE_HEAD	DW	0H ; head of queue - READ FROM HEAD
	SERIAL_QUEUE_TAIL	DW	0H ; tail of queue - WRITE TO TAIL
	SERIAL_QUEUE_READY 	DB  0

;RECEIVED PACKAGE
	RECEIVE_TAIL	DB 0
	RECEIVE_HEAD	DB 0
	RECEIVE_ARR		DB 8 DUP(?)

;TOTAL PAYMENT AMOUNT
	CURRENT_QUANTITY	DB 0
	CURRENT_PRICE		DW 0
	CURRENT_AMOUNT 		DW 0
	TOTAL_AMOUNT		DW 0
	AMOUNT_TENDER 		DW 0

	AMOUNT_TENDER_H		DW 0
	CURRENT_AMOUNT_H	DW 0
	TOTAL_AMOUNT_H		DW 0
;Header
	HEADER_MATCH DB 0 ;count number of byte match
	HEADER_IDX DB 0

	HEADER db '1','1','0','5','4'
;	HEADER db '1','0','0','0','1'

DATA_SEG	ENDS

;=============================================================================
SOUND_SEG	SEGMENT

	; ------- SOUND OFFSET -------
	SOUND_30				EQU	21
	SOUND_40				EQU	22
	SOUND_50				EQU	23
	SOUND_60				EQU	24
	SOUND_70				EQU	25
	SOUND_80				EQU	26
	SOUND_90				EQU	27
	SOUND_HUNDRED			EQU	28
	SOUND_THOUSAND			EQU	29
	
	SOUND_ADD 				EQU 30	;new
	SOUND_AMOUNT_TENDERED	EQU 31
	SOUND_AND				EQU	32
	SOUND_BARCODE			EQU 33	;new
	SOUND_CANCEL			EQU 34	;new

	SOUND_WELCOME			EQU 35	;NEW
	SOUND_CENTS				EQU	36
	SOUND_CODE 				EQU 37	;NEW
	SOUND_DOLLARS			EQU	38
	SOUND_ERROR				EQU 39
	
	SOUND_FAIL 				EQU 40	;NEW
	SOUND_PRODUCT 			EQU 41	;NEW
	SOUND_QUANTITY 			EQU 42	;NEW
	SOUND_REMOVE 			EQU 43	;NEW
	SOUND_SUBTOTAL 			EQU 44	;NEW

	SOUND_THANK_YOU			EQU 45
	SOUND_TOTAL				EQU	46
	SOUND_TRANSACTION		EQU 47	;NEW
	SOUND_YOUR_CHANGE		EQU 48
	SOUND_SINGYA 			EQU 49	;NEW

	SOUND_SO_COOL 			EQU 50	;NEW
	SOUND_DONT_PANIC 		EQU 51	;NEW
	SOUND_BEEP				EQU 52
	SOUND_SUCCESS_BEEP		EQU 53
	SOUND_LOGIN				EQU 35 	;CHANGE TO 'WELCOME_TO_CEG_HYPERMARKETT'!
	; ----------------------------
							; 0 - 4
	SoundOffsetAddr			DD    800,  4920,  8716, 11611, 14732
							; 5 - 9
							DD  17347, 20383, 23026, 26568, 29577
							; 10 - 14
							DD  33316, 36493, 41610, 46024, 51506
							; 15 - 19
							DD  56707, 61712, 67250, 72873, 77709
							; 20, 30, 40, 50, 60
							DD  84400, 89151, 93537, 97979, 101972
							; 70, 80, 90, 100, 1000
							DD  106442, 111334, 115101, 120049, 124632
							; add,amount_tendered, and, barcode, cancel
							DD  129411, 132054, 140798, 143975, 149064
							; Welcome to CEG Hypermarket, cents, code, dollars, error
							DD  154546, 172792, 176391, 179287, 182801	
							; fail, product, quantity, remove, subtotal
							DD  186090, 189464, 194328, 200035, 204534
							; thank you, total, transaction, your change, Singya
							DD  211225, 216173, 220587, 227953, 234757
							;So Cool, Don't Panic, beep, success beep
							DD  238665, 243529, 251063, 252947
							
							; 0 - 4
	SoundLen				DW	3895, 3739, 2755, 2980, 2502
							; 5 - 9
							DW	3008, 2558, 3599, 2924, 3683
							; 10 - 14
							DW 3149, 4779, 4329, 4414, 4245
							; 15 - 19
							DW 4135, 4807, 5117, 4133, 5426
							; 20, 30, 40, 50, 60
							DW 4695, 4302, 4302, 3824, 4442
							; 70, 80, 90, 100, 1000
							DW 4836, 3655, 4751, 3177, 3936
							; add, amount_tendered, and, barcode, cancel
							DW 2221, 7704, 2418, 4105, 4807
							; Welcome to CEG Hypermarket, cents, code, dollars, error
							DW 16447, 2137,2100,2558,2811
							; fail, product, quantity, remove, subtotal
							DW 2418,3065,5201,3149,5313
							; thank you, total, transaction, your change, Singya
							DW 4020,3346,6748,5595,3542
							;So Cool, Don't Panic, beep, success beep
							DW 4498,5932,1912,4701

	SOUND_ARRAY_LEN			EQU 32	; Max. no. of sound samples on array
	SoundArray				DB	SOUND_ARRAY_LEN DUP(?)
	SoundArrayEnd			DW	0
	SoundArrayStart			DW	0
	SoundArrayCount			DW	0
	SoundAddr				DD 	0
	SoundBytesLeft			DW	0

	ROM_BASE_ADDR 			EQU 4000H
SOUND_SEG	ENDS
;=============================================================================

; DATA segment for debug messages
DEBUG_SEG segment
	DEBUG_AL	DB  10,13,'current AL =    '
	DEBUG_T1 	DB 	10,13,'T1-Period =    '
	DEBUG_T2 	DB 	10,13,'T2-Period =    '
	DEBUG_KEYPAD_INPUT DB 10,13,'KEYPAD INPUT    '
	DEBUG_DEQUEUE DB  10,13,'Dequeue    '
	DEBUG_PRIORITY DB 10,13,'collision..... T1 has priority'
DEBUG_SEG ENDS


CODE_SEG	SEGMENT
PUBLIC		START
	PPI_8255_PORTA EQU 080H ;port a
	PPI_8255_PORTB EQU 081H ;port b
	PPI_8255_PORTC EQU 082H ;port c
	PPI_8255_CWR EQU 083H ;command word register
	PCS0 EQU 000H
	PCS1 EQU 080H
	PCS2 EQU 100H
	PCS3 EQU 180H
	PCS4 EQU 200H

;to store the address of the queue space
	KEY_QUEUE_BASE EQU OFFSET KEY_QUEUE_TRANS
	SERIAL_QUEUE_BASE EQU OFFSET SERIAL_QUEUE_TRANS
	PACKAGE_BASE EQU OFFSET PACKAGE_ARR

	END_BYTE EQU 'z'
	HEADER_LEN EQU 5

$include(80188.inc)

ASSUME	CS:CODE_SEG, SS:STACK_SEG, DS:DATA_SEG, ES:SOUND_SEG
RESET PROC FAR
;	call far ptr PRINTLN_DEBUG
RESET endp
START:
; Initialize MPCS to MAP peripheral to IO address
    MOV DX, MPCS
    MOV AX, 2083H
    OUT DX, AL  
; Initialize MMCR to MAP external Memory
    MOV DX, MMCR
    MOV AX, 4003H
    OUT DX, AL
; PCSBA initial, set the serial port start from 00H
    MOV DX, PCSBA
    MOV AX, 0003H ; Peripheral starting address 00H no READY, No Waits
    OUT DX, AL

;initialize stack area
	MOV	AX,STACK_SEG		
	MOV	SS,AX
	MOV	SP,TOS

;initialize data segment register
	MOV	BX,DATA_SEG		
	MOV	DS,BX	

	MOV	AX,SOUND_SEG
	MOV	ES,AX

; Set CWR - All output
	MOV DX,PPI_8255_CWR
	MOV	AL,82H
	OUT DX,AL

	mov DS:KEY_QUEUE_READY,0
	mov DS:SERIAL_QUEUE_READY,0

	mov DS:KEY_QUEUE_TAIL,0
	mov ds:KEY_QUEUE_HEAD,0
	mov ds:SERIAL_QUEUE_TAIL,0
	mov ds:SERIAL_QUEUE_HEAD,0

	mov ds:CURRENT_PRICE,0
	mov ds:CURRENT_QUANTITY,0
	mov ds:CURRENT_AMOUNT,0
	mov ds:TOTAL_AMOUNT,0

	mov ds:CURRENT_AMOUNT_H,0
	mov ds:TOTAL_AMOUNT_H,0


	mov DS:header_match,0
	mov ds:HEADER_IDX,0

	mov ds:SegNum[0],10
	mov ds:SegNum[1],10
	mov ds:SegNum[2],10
	mov ds:SegNum[3],10
	mov ds:SegNum[4],10
	mov ds:SegNum[5],10

; Initialize the on-chip pheripherals
	CALL	FAR PTR	IODEFINE
; ^^^^^^^^^^^^^^^^^  Start of User Main Routine  ^^^^^^^^^^^^^^^^^^
	call far ptr set_timers
	STI

MAIN_LOOP:
; if(), if(), if() - no priority checking
; all the process (in total of three processes) will run 
	mov AL,DS:T1
	cmp AL,00h
	je T1_ACTION
Proc_1_end:
	
	mov AX,DS:T2
	cmp AX,00h
	je T2_ACTION
Proc_2_end:
	jmp MAIN_LOOP

T1_ACTION:
;reset counter back to the top counter value, and it will decrement the value itself
	mov AL,DS:T1_top
	mov DS:T1,AL
;print current time	
;	mov AL,DS:COUNTER
;	mov BL,DS:T1_prev
;	sub AL,BL
;
;	cmp AL,DS:T1_top
;	je START_T1
;	call far ptr PRINT_T1_PERIOD_DEBUG

START_T1:
;{------------------- LOOP T1 -----------------------
	call far ptr READ_KEYPAD

; if(new_key=previous_key)
; 	break
	cmp AL,DS:KEY_PREV
	je END_READ_KEYPAD

; else
;	previous_key = new_key
;	if(new_key=no_key)
;		break
	mov DS:KEY_PREV,AL
	cmp AL,0FFh
	je END_READ_KEYPAD

; 	else
;		q.push(new_key)
;		display new_key

	call far ptr KEY_ENQUEUE

	call far ptr DISPLAY_SHIFT_LEFT ;add AL to the end!

;!!!sound!!!!
	call far ptr SPEAKER_KEYPAD_INPUT

;	call far ptr PRINT_KEYPAD_INPUT_DEBUG

;		if(AL=DEL)
;			if(!Q.empty())
;				Q.pop()
	cmp AL,10
	jne FINISH_DEL_1_ELEMENT
		dec DS:KEY_QUEUE_TAIL		;remove del key
		mov BX,DS:KEY_QUEUE_HEAD
		cmp BX,DS:KEY_QUEUE_TAIL
		je FINISH_DEL_1_ELEMENT
		dec DS:KEY_QUEUE_TAIL		;remove the prev key
	FINISH_DEL_1_ELEMENT:

;		if (AL!=ENTER)
;			break
;		else
;			set queue_ready
	cmp AL,11
	jne END_READ_KEYPAD
	inc DS:KEY_QUEUE_READY
;	mov AL,DS:KEY_QUEUE_READY
;	call far ptr PRINT_AL_DEBUG
;	call far ptr PRINTLN_DEBUG


END_READ_KEYPAD:

;------------------- LOOP T1 -----------------------}
	mov AL,DS:COUNTER
	mov DS:T1_prev,AL
	JMP Proc_1_end

T2_ACTION:
;reset counter
	mov AX,DS:T2_top
	mov DS:T2,AX
;print current time	
;	mov AL,DS:COUNTER
;	mov BL,DS:T2_prev
;	sub AL,BL
;	call far ptr PRINT_T2_PERIOD_DEBUG

;{------------------- LOOP T2 -----------------------
;PART1: TRANSMIT: CASHIER --> SHOP PC
;if (key_queue_ready != 1)
;	break
	cmp KEY_QUEUE_READY,0
	je END_TRANSMIT
;else

;	initialize empty PACKAGE array
	MOV DS:PACKAGE_TAIL,0
	MOV DS:PACKAGE_HEAD,0
;do{
;	if(!Q.empty())
;		AL = Q.POP() 
;	else	
;		break
START_KEY_DEQUEUE:
	MOV BX,DS:KEY_QUEUE_TAIL
	CMP BX,DS:KEY_QUEUE_HEAD ; return if the tail is the same as head 
	JE END_TRANSMIT ; if Queue is empty: skip

	MOV BX,DS:KEY_QUEUE_HEAD
	MOV AL,DS:KEY_QUEUE_BASE[BX]
	
	inc DS:KEY_QUEUE_HEAD
	cmp DS:KEY_QUEUE_HEAD,KEY_QUEUE_LEN
	JL FINISH_KEY_DEQUEUE		;if head >= len, wrap around
	MOV DS:KEY_QUEUE_HEAD,0
FINISH_KEY_DEQUEUE:
;encode --> PACKAGE
;	PACKAGE[tail] = AL
;	tail++
	;normal case, write to tail
	XOR BX,BX
	MOV BL,DS:PACKAGE_TAIL
	MOV DS:PACKAGE_ARR[BX],AL
	INC DS:PACKAGE_TAIL

;}while(AL != enter) 
;loop back to dequeue
	cmp AL,11 ;enter key
	jne START_KEY_DEQUEUE
;clear queue_ready
	DEC DS:KEY_QUEUE_READY
;	mov AL,DS:KEY_QUEUE_READY
;	call far ptr PRINT_AL_DEBUG
;	call far ptr PRINTLN_DEBUG

;--------------------------------------------------
;sending PACKAGE after finish encoding PACKAGE
	CALL FAR PTR PROCESS_PACKAGE
END_TRANSMIT:
;--------------------------------------------------
;PART2: RECEIVE: CASHIER <-- SHOP PC

;if( serial_queue_ready !=1)
;	break
	cmp serial_queue_ready,0
	je END_RECEIVE

	MOV DS:RECEIVE_HEAD,0
	MOV DS:RECEIVE_TAIL,0
;do{
;	if(!serialQ.empty())
;		AL = serialQ.POP() 
;	else	
;		break
START_SERIAL_DEQUEUE:
	MOV BX,DS:SERIAL_QUEUE_TAIL
	CMP BX,DS:SERIAL_QUEUE_HEAD ; return if the tail is the same as head 
	JE END_TRANSMIT ; if Queue is empty: skip

	MOV BX,DS:SERIAL_QUEUE_HEAD
	MOV AL,DS:SERIAL_QUEUE_BASE[BX]
	
	inc DS:SERIAL_QUEUE_HEAD
	cmp DS:SERIAL_QUEUE_HEAD,SERIAL_QUEUE_LEN
	JL FINISH_SERIAL_DEQUEUE		;if head >= len, wrap around
	MOV DS:SERIAL_QUEUE_HEAD,0

FINISH_SERIAL_DEQUEUE:
;while(AL!=end_byte){
	cmp AL,END_BYTE
	je SERIAL_END_BYTE

;	receive_arr.add(AL-48)
	sub AL,48 ;convert ASCII to num

	XOR BX,BX
	MOV BL,DS:RECEIVE_TAIL
	MOV DS:RECEIVE_ARR[BX],AL
	INC DS:RECEIVE_TAIL
;} loop back to serial dequeue
	jmp START_SERIAL_DEQUEUE
;clear serialQ ready
SERIAL_END_BYTE:
	dec ds:serial_queue_ready
	call far ptr PROCESS_RECEIVED_DATA
END_RECEIVE:
;---------------------------------------------------}
	mov AL,DS:COUNTER
	mov DS:T2_prev,AL
	JMP Proc_2_end

; ^^^^^^^^^^^^^^^ End of User main routine ^^^^^^^^^^^^^^^^^^^^^^^^^
SERIAL_REC_ACTION	PROC	FAR
	PUSH 	BX
	PUSH	DS

	MOV	BX,DATA_SEG		;initialize data segment register
	MOV	DS,BX

;debug
;	mov BL,AL
;	call far ptr print_char
;	mov al,Bl
;----

;if(headerID != header_len) -- still in header 
;	check header -> skip
	CMP DS:HEADER_IDX,HEADER_LEN
	JAE CONTENT_CHECK
	
	CALL HEADER_CHECK
;debug	
;	mov AL,DS:HEADER_IDX
;	call far ptr print_2hex
;----
	JMP serial_action_end
;else -- not in header
CONTENT_CHECK:
;	if(HEADER_MATCH == HEADER_LEN)
;		receive until end byte
;	else -- discard message if not recipient 
;		wait until end byte to reset
	CMP DS:HEADER_MATCH,HEADER_LEN
	jne DISCARD_MESSAGE

	call PROCESS_CONTENT

	JMP serial_action_end

DISCARD_MESSAGE:
	CMP AL,END_BYTE
	jne serial_action_end
	mov ds:HEADER_MATCH,0
	mov ds:HEADER_IDX,0

serial_action_end:
	POP	DS
	POP	BX
	RET
SERIAL_REC_ACTION	ENDP

;------------------------------------------
PROCESS_CONTENT proc near
	CALL FAR PTR SERIAL_ENQUEUE
	cmp AL,END_BYTE ;END BYTE
	jne FINISH_PROCESS_CONTENT

;enable logic flag
	inc DS:SERIAL_QUEUE_READY
;	mov AL,DS:SERIAL_QUEUE_READY
;	call far ptr PRINT_AL_DEBUG
;	call far ptr PRINTLN_DEBUG

;clear header
	mov ds:HEADER_MATCH,0
	mov ds:HEADER_IDX,0
FINISH_PROCESS_CONTENT:
	RET
PROCESS_CONTENT ENDP


;------------------------------------------
HEADER_CHECK proc near
	push BX

	XOR BX, BX
	MOV bl, DS:HEADER_IDX
 
;if (!header_match)
;	skip
;else
;	increase header_match counter

	CMP AL, DS:HEADER[BX]
	JNE END_HEADER_CHECK

	INC DS:HEADER_MATCH
	
;	mov al,DS:header_match
;	call far ptr print_2hex
END_HEADER_CHECK:	

	INC DS:HEADER_IDX ;check the next header byte

	pop BX
	ret
HEADER_CHECK endp

;+++++++++++++++++++++++++++++++ TIMER2_ACTION ++++++++++++++++++++++++++++++
;=================================== SOUND ==================================
TIMER2_ACTION	PROC	FAR

		PUSH AX
		PUSH BX
		PUSH DX
		PUSH DS
		PUSH ES
		
		MOV DX, SOUND_SEG
		MOV DS, DX

		;Check if current sound sample is playing
		CMP DS:SoundBytesLeft, 0
		JNE PLAY_SOUND

	; ENQUEUE_TEST:
		;CALL NEAR PTR PLAY_TEST_SOUND
		; ;MOV AL, DS:SOUND_QUEUE_COUNT
		; ;CALL FAR PTR PRINT_2HEX

		;Check if sound queue is empty
		CMP DS:SoundArrayCount, 0
		JG DEQUEUE_SOUND
		
		;Disable Timer2 to free up CPU resource
		MOV AX, 6001H
		MOV DX, T2_CON
		OUT DX, AL
		JMP EXIT_TMR2
	
		
	DEQUEUE_SOUND:
		XOR BX, BX
		MOV SI, DS:SoundArrayStart
		MOV BL, DS:SoundArray[SI]	;Put the sound sample offset to BL
		SHL BX, 2 					;Align the index due to DD array
		
		;Get offset address of sound sample
		MOV AX, WORD PTR DS:SoundOffsetAddr[BX]
		MOV WORD PTR DS:SoundAddr[2], AX
		MOV AX, WORD PTR DS:SoundOffsetAddr[BX][2]
		MOV WORD PTR DS:SoundAddr[0], AX
		
		;Get the size of sound sample
		SHR BX, 1 					;Align the index from DD to DW array
		MOV AX, DS:SoundLen[BX]
		MOV DS:SoundBytesLeft, AX
		
		;Shift pointer of sound array
		DEC DS:SoundArrayCount					;reduce total count
		INC DS:SoundArrayStart					;points to next element
		CMP DS:SoundArrayStart, SOUND_ARRAY_LEN	;if start = length, pointer wrap around array
		JL PLAY_SOUND							;else, continue to play sound
		MOV DS:SoundArrayStart, 0
		
	PLAY_SOUND:
		;Set segment address
		MOV BX, ROM_BASE_ADDR
		MOV AX, WORD PTR DS:SoundAddr[0]
		SHL AX, 12
		ADD BX, AX	; Once offset past FFFFh, base address increases by 1000h.
		MOV ES, BX
		
		;Get sound data
		MOV BX, WORD PTR DS:SoundAddr[2]
		MOV AL, ES:[BX]
		
		;Output to DAC
		MOV DX, PCS4
		OUT DX, AL
		
	;shift to the next sound data address
		DEC DS:SoundBytesLeft
		CMP WORD PTR DS:SoundAddr[2], 0FFFFH
		JNE INC_LOWER_SOUND_ADDR
		INC WORD PTR DS:SoundAddr[0]
	INC_LOWER_SOUND_ADDR:
		INC WORD PTR DS:SoundAddr[2]
		
	EXIT_TMR2:
		POP ES
		POP DS
		POP DX
		POP BX
		POP AX
		RET

TIMER2_ACTION	ENDP
;+++++++++++++++++++++++++++++++ TIMER2_ACTION ++++++++++++++++++++++++++++++
;===========================================
SPEAKER_KEYPAD_INPUT PROC FAR
	push ax
	
	cmp al, 1
	je	SAY_ONE
	
	cmp al, 2
	je SAY_TWO
	
	cmp al, 3
	je	SAY_THREE
	
	cmp al, 4
	je SAY_FOUR
	
	cmp al, 5
	je SAY_FIVE
	
	cmp al, 6
	je SAY_SIX
	
	cmp al, 7
	je	SAY_SEVEN
	
	cmp al, 8
	je SAY_EIGHT
	
	cmp al, 9
	je	SAY_NINE
	
	cmp al, 0
	je	SAY_ZERO
	
	cmp AL,10
	je SAY_BEEP

	cmp al, 11
	je	SAY_SUCCESS_BEEP
	
	jmp SAY_SECOND_KEYPAD

	
	SAY_ONE:
		MOV AL, 1
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_TWO:
		MOV AL, 2
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_THREE:
		MOV AL, 3
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_FOUR:
		MOV AL,4
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_FIVE:
		MOV AL,5
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_SIX:
		MOV AL,6
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_SEVEN:
		MOV AL,7
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_EIGHT:
		MOV AL,8
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_NINE:
		MOV AL,9
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1
	SAY_ZERO:
		MOV AL,0
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1

	SAY_SUCCESS_BEEP:
		MOV AL,SOUND_SUCCESS_BEEP
		CALL FAR PTR ENQUEUE_SOUND
		jmp END_SPEAKER_KEY_INPUT1

	SAY_BEEP:
		MOV AL,SOUND_BEEP
		CALL FAR PTR ENQUEUE_SOUND
		jmp	END_SPEAKER_KEY_INPUT1

	END_SPEAKER_KEY_INPUT1:
		JMP END_SPEAKER_KEY_INPUT2

	SAY_SECOND_KEYPAD:

	CMP al,15
	JE SAY_ADD

	CMP al,16
	JE SAY_QUANTITY

	CMP al,17
	JE SAY_REMOVE

	CMP AL,18
	JE SAY_TOTAL

	CMP AL,21
	JE SAY_SO_COOL

	CMP AL,22
	JE SAY_DONT_PANIC

	JMP SAY_BEEP

	SAY_ADD:
		MOV AL,SOUND_ADD
		CALL FAR PTR ENQUEUE_SOUND
		jmp END_SPEAKER_KEY_INPUT2

	SAY_QUANTITY:
		MOV AL,SOUND_QUANTITY
		CALL FAR PTR ENQUEUE_SOUND
		jmp END_SPEAKER_KEY_INPUT2

	SAY_REMOVE:
		MOV AL,SOUND_REMOVE
		CALL FAR PTR ENQUEUE_SOUND
		jmp END_SPEAKER_KEY_INPUT2

	SAY_TOTAL:
		MOV AL,SOUND_SUBTOTAL
		CALL FAR PTR ENQUEUE_SOUND
		jmp END_SPEAKER_KEY_INPUT2

	SAY_SO_COOL:
		MOV AL,SOUND_SO_COOL
		CALL FAR PTR ENQUEUE_SOUND
		jmp END_SPEAKER_KEY_INPUT2	
	
	SAY_DONT_PANIC:
		MOV AL,SOUND_DONT_PANIC
		CALL FAR PTR ENQUEUE_SOUND
		jmp END_SPEAKER_KEY_INPUT2
	
	END_SPEAKER_KEY_INPUT2:
		pop ax
		ret
SPEAKER_KEYPAD_INPUT ENDP

; Enqueues a sound sample into the sound array
; The sound samples will automatically be dequeued and executed by Timer2
; Note: Sound sample in AL
ENQUEUE_SOUND PROC FAR
		PUSH AX
		PUSH BX
		PUSH DX
		PUSH DS
		
		;DS points to sound segment
		MOV DX, SOUND_SEG
		MOV DS, DX
		
		;If count = length, array is full
		CMP DS:SoundArrayCount, SOUND_ARRAY_LEN
		JE EXIT_SOUND_ENQUEUE
		
		;Else, input sample into array
		MOV BX, DS:SoundArrayEnd
		MOV DS:SoundArray[BX], AL
		INC DS:SoundArrayCount
		INC DS:SoundArrayEnd
		CMP DS:SoundArrayEnd, SOUND_ARRAY_LEN	;if end = length, pointer wraps around the array
		JNE ENABLE_TIMER2
		MOV DS:SoundArrayEnd, 0
		
	ENABLE_TIMER2:
		MOV AX, 0E001H
		MOV DX, T2_CON
		OUT DX, AL
		
	EXIT_SOUND_ENQUEUE:
		POP DS
		POP DX
		POP BX
		POP AX
		RET
ENQUEUE_SOUND ENDP

PLAY_TEST_SOUND PROC FAR
		PUSH AX
		PUSH BX
		PUSH DX
		PUSH CX

		mov CX,AX

		XOR DX,DX
		XOR AX,AX
		XOR BX,BX
		MOV AL,CH
		MOV BL,10
		MUL BL
		ADD AL,CL

		CALL ENQUEUE_SOUND
	
		POP CX
		POP DX
		POP BX
		POP AX
		RET
PLAY_TEST_SOUND ENDP

SPEAK_2DIGITS proc far
;store 2 DECIMAL DIGITS in AH and AL
	PUSH AX
	push BX
	push DX

	mov DX,AX

	mov AL,DH
	CMP AL,2
	JB SAY_00_TO_19
	;SAY_20_TO_99:
		mov AL,DH
		add AL,18 ;map function to map from '2' ->20, '3'->30 
		CALL ENQUEUE_SOUND

		mov AL,DL
		cmp AL,0
		je END_SPEAKER_2DIGITS

		CALL ENQUEUE_SOUND
		jmp END_SPEAKER_2DIGITS
	SAY_00_TO_19:
		XOR AX,AX
		MOV AL,DH
		MOV BL,10
		MUL BL
		ADD AL,DL

		CALL ENQUEUE_SOUND
END_SPEAKER_2DIGITS:
	pop DX
	pop BX
	POP ax
	ret
SPEAK_2DIGITS endp

SAY_AMOUNT_DISPLAYED proc far
	PUSH DS
	PUSH AX
	PUSH BX

	MOV AX,DATA_SEG
	MOV DS,AX
;DISABLE SPEAKER
;	MOV AX, 06001H
;	MOV DX, T2_CON
;	OUT DX, AL
;
;	mov AL,DS:SegNum[0]
;	call far ptr PRINT_2HEX
;	mov AL,DS:SegNum[1]
;	call far ptr PRINT_2HEX
;	mov AL,DS:SegNum[2]
;	call far ptr PRINT_2HEX
;	mov AL,DS:SegNum[3]
;	call far ptr PRINT_2HEX
;	mov AL,DS:SegNum[4]
;	call far ptr PRINT_2HEX
;	mov AL,DS:SegNum[5]
;	call far ptr PRINT_2HEX

	CMP DS:SegNum[0],0
	je SKIP_SAY_THOUSAND
		MOV AL,DS:SegNum[0]
		CALL ENQUEUE_SOUND
		MOV AL,SOUND_THOUSAND
		CALL ENQUEUE_SOUND
	SKIP_SAY_THOUSAND:
	CMP DS:SegNum[1],0
	JE SKIP_SAY_HUNDRED
		MOV AL,DS:SegNum[1]
		CALL ENQUEUE_SOUND
		MOV AL,SOUND_HUNDRED
		CALL ENQUEUE_SOUND
	SKIP_SAY_HUNDRED:
	MOV AH,DS:SegNum[2]
	MOV AL,DS:SegNum[3]
	CALL FAR PTR SPEAK_2DIGITS

	MOV AL,SOUND_DOLLARS
	CALL ENQUEUE_SOUND

	MOV AL,SOUND_AND
	CALL ENQUEUE_SOUND

	MOV AH,DS:SegNum[4]
	MOV AL,DS:SegNum[5]
	CALL FAR PTR SPEAK_2DIGITS

	MOV AL,SOUND_CENTS
	CALL ENQUEUE_SOUND
FINISH_SPEAK_SUBTOTAL:
	POP BX
	POP AX
	POP DS
	RET	
SAY_AMOUNT_DISPLAYED endp
;=================================== ^SOUND^ ================================
;+++++++++++++++++++++++++++++++ TIMER2_ACTION ++++++++++++++++++++++++++++++


;+++++++++++++++++++++++++++++++ TIMER1_ACTION ++++++++++++++++++++++++++++++
TIMER1_ACTION	PROC	FAR
	PUSH	AX
	PUSH	DS
	PUSH	BX
	PUSH	CX

	MOV	AX,DATA_SEG
	MOV	DS,AX

;DISABLE SPEAKER
	MOV AX, 06001H
	MOV DX, T2_CON
	OUT DX, AL

	call far ptr display7segment

	MOV AL,DS:T1
	CMP AL,00H
	JE FINISH_ENABLE_T1
	DEC AL 		;Decrement T1_Counter
	MOV DS:T1,AL

FINISH_ENABLE_T1:
	MOV AX,DS:T2
	CMP AX,00H
	JE FINISH_ENABLE_T2
	DEC DS:T2 	;Decrement T2_Counter

FINISH_ENABLE_T2:
	mov AL,DS:COUNTER
	inc AL
	mov DS:COUNTER,AL

END_TIMER1_ACTION:	

;ENABLE SPEAKER	
	MOV AX, 0E001H
	MOV DX, T2_CON
	OUT DX, AL


	POP	CX
	POP	BX
	POP	DS
	POP AX
	RET
TIMER1_ACTION	ENDP
;+++++++++++++++++++++++++++++++ TIMER1_ACTION ++++++++++++++++++++++++++++++
;*************** SUPPORT FUNCTIONS ***************
$include(keypad.inc)
$include(7seg.inc)
$include(debug.inc)

KEY_ENQUEUE proc far
	push BX

	mov BX,DS:KEY_QUEUE_TAIL
	MOV DS:KEY_QUEUE_BASE[BX],AL 		;enqueue AL to the tail of queue
	
	INC DS:KEY_QUEUE_TAIL 				;to next element (increase value)
	CMP DS:KEY_QUEUE_TAIL,KEY_QUEUE_LEN ;return once it reaches the end 
	JL END_KEY_ENQUEUE
	MOV DS:KEY_QUEUE_TAIL,0 ;wrap around when reach end of queue

 END_KEY_ENQUEUE:
	pop BX
	ret	
KEY_ENQUEUE endp

SERIAL_ENQUEUE proc far
	push BX

	mov BX,DS:SERIAL_QUEUE_TAIL
	MOV DS:SERIAL_QUEUE_BASE[BX],AL 		;enqueue AL to the tail of queue
	
	INC DS:SERIAL_QUEUE_TAIL 				;to next element (increase value)
	CMP DS:SERIAL_QUEUE_TAIL,SERIAL_QUEUE_LEN ;return once it reaches the end 
	JL END_SERIAL_ENQUEUE
	MOV DS:SERIAL_QUEUE_TAIL,0 ;wrap around when reach end of queue

 END_SERIAL_ENQUEUE:
	pop BX
	ret	
SERIAL_ENQUEUE endp
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;===================================================================
PROCESS_PACKAGE proc far
	PUSH AX
	PUSH BX
	PUSH CX

;read from head, head is initialized to 0
	MOV DS:PACKAGE_HEAD,0

;check command
	cmp DS:PACKAGE_ARR[0],14 ;End transaction, get money from user
	JE CMD_14

	cmp DS:PACKAGE_ARR[0],15 ;add
	JE CMD_15_17

	CMP DS:PACKAGE_ARR[0],17 ;REMOVE
	JE CMD_15_17

	cmp DS:PACKAGE_ARR[0],18 ;display total amount
	je CMD_18

	cmp DS:PACKAGE_ARR[0],19 ;display current amount
	je CMD_19

	cmp DS:PACKAGE_ARR[0],20 ;play test_sound
	je CMD_20

	cmp ds:PACKAGE_ARR[0],21 ;

	cmp DS:PACKAGE_ARR[0],23 ;reset counter
	je CMD_23
;else
	CALL FAR PTR SEND_PACKAGE
	JMP FINISH_PROCESS_PACKAGE

CMD_14: ;END TRANSACTION GET MONEY FROM USER
	;mov AL,SOUND_AMOUNT_TENDERED
	;call far ptr ENQUEUE_SOUND
	;CALL far PTR DISPLAY_AMOUNT_TENDERED
	;call far ptr SAY_AMOUNT_DISPLAYED

CMD_15_17: ;ADD/REMOVE
;-----------------------------------------------------------
;ADD/REMOVE FORMAT: 
;	0                  9            10  11  12
;	12(add), 12345678 ,16(quantity),1   0,  11(end) 
;-----------------------------------------------------------
	call far ptr SEND_PACKAGE
	call far ptr UPDATE_QUANTITY
	jmp FINISH_PROCESS_PACKAGE

CMD_18: ;DISPLAY
	CALL FAR PTR DISPLAY_TOTAL_AMOUNT
	CALL FAR PTR SAY_AMOUNT_DISPLAYED

	jmp FINISH_PROCESS_PACKAGE
CMD_19: ;DISPLAY current Price x Units
	CALL FAR PTR DISPLAY_CURRENT_AMOUNT

	jmp FINISH_PROCESS_PACKAGE

CMD_20:
	mov AH,DS:PACKAGE_ARR[1]
	mov AL,DS:PACKAGE_ARR[2]
	call far ptr PLAY_TEST_SOUND

	jmp FINISH_PROCESS_PACKAGE

CMD_21:
	jmp FINISH_PROCESS_PACKAGE
CMD_23:
;	MOV AL,0F1H
;	CALL FAR PTR PRINT_2HEX
;
;	mov AL,DS:PACKAGE_ARR[1]
;	cmp AL,DS:HEADER[1]
;	JNE FINISH_PROCESS_PACKAGE
;
;	MOV AL,0F2H
;	CALL FAR PTR PRINT_2HEX
;
;	mov AL,DS:PACKAGE_ARR[2]
;	cmp AL,DS:HEADER[2]
;	JNE FINISH_PROCESS_PACKAGE
;
;	MOV AL,0F3H
;	CALL FAR PTR PRINT_2HEX
;
;	mov AL,DS:PACKAGE_ARR[3]
;	cmp AL,DS:HEADER[3]
;	JNE FINISH_PROCESS_PACKAGE
;
;	MOV AL,0F4H
;	CALL FAR PTR PRINT_2HEX
;
;	mov AL,DS:PACKAGE_ARR[4]
;	cmp AL,DS:HEADER[4]
;	JNE FINISH_PROCESS_PACKAGE
;
;	MOV AL,0F5H
;	CALL FAR PTR PRINT_2HEX
;
	PUSH DS
	MOV AX,SOUND_SEG
	MOV DS,AX

	MOV AL,SOUND_WELCOME
	CALL FAR PTR ENQUEUE_SOUND
	POP DS

;	MOV AL,0F6H
;	CALL FAR PTR PRINT_2HEX
;

	call far ptr RESET
	JMP FINISH_PROCESS_PACKAGE

FINISH_PROCESS_PACKAGE:
;	call far ptr print_2hex

	POP CX
	POP BX
	POP AX
	ret
PROCESS_PACKAGE endp

;===================================================================
SEND_PACKAGE proc far
;DISABLE SPEAKER
	MOV AX, 06001H
	MOV DX, T2_CON
	OUT DX, AL

	XOR BX,BX
	XOR AX,AX
SEND_HEADER:
	MOV Al,DS:HEADER[BX]
	CALL FAR PTR PRINT_CHAR
	INC BX

	CMP BX,HEADER_LEN
	JB SEND_HEADER

;SEND BODY
START_SENDING_PACKAGE:

	MOV AL,DS:PACKAGE_TAIL
	CMP AL,DS:PACKAGE_HEAD
	JE END_SENDING_PACKAGE

	XOR BX,BX
	MOV BL,DS:PACKAGE_HEAD
	MOV AL,DS:PACKAGE_ARR[BX]
	inc DS:PACKAGE_HEAD

	add AL,'0' ;convert to ASCII
	CALL FAR PTR PRINT_CHAR

	JMP START_SENDING_PACKAGE
END_SENDING_PACKAGE:
;ENABLE SPEAKER	
	MOV AX, 0E001H
	MOV DX, T2_CON
	OUT DX, AL

	RET
SEND_PACKAGE endp

;-----------------------------------------------------
UPDATE_QUANTITY proc far
	mov DS:CURRENT_QUANTITY,0
	mov al,DS:PACKAGE_TAIL
	cmp al,13
	JNE ONE_DIGIT_QUANTITY
;	if(size=13) (2-bit quantity)
;		CURRENT_QUANTITY = ARR[10]*10+ARR[11]
		XOR AX,AX
		MOV AL,DS:PACKAGE_ARR[10]
		MOV BL,10
		MUL BL
		ADD AL,DS:PACKAGE_ARR[11]
		MOV DS:CURRENT_QUANTITY,AL
		JMP FINISH_CONVERT_QUANTITY
	ONE_DIGIT_QUANTITY:
;	else
;		CURRENT_QUANTITY = ARR[10]
		MOV AL,DS:PACKAGE_ARR[10]
		MOV DS:CURRENT_QUANTITY,AL

	FINISH_CONVERT_QUANTITY:
;	print quantity [debug]
;		MOV AL,DS:CURRENT_QUANTITY
;		CALL FAR PTR PRINT_AL_DEBUG
;		CALL FAR PTR PRINTLN_DEBUG
	ret
UPDATE_QUANTITY endp
;-----------------------------------------------------
;display on the LCD screen
DISPLAY_TOTAL_AMOUNT proc far
	MOV DS:Display_isNumber,1

	mov DX,DS:TOTAL_AMOUNT_H
	mov AX,DS:TOTAL_AMOUNT

	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[5],DL

;	CMP AX,0
;	JE END_DISPLAY_TOTAL_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[4],DL

;	CMP AX,0
;	JE END_DISPLAY_TOTAL_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[3],DL

;	CMP AX,0
;	JE END_DISPLAY_TOTAL_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[2],DL

;	CMP AX,0
;	JE END_DISPLAY_TOTAL_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[1],DL

;	CMP AX,0
;	JE END_DISPLAY_TOTAL_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[0],DL

END_DISPLAY_TOTAL_PRICE:
	RET
DISPLAY_TOTAL_AMOUNT ENDP

DISPLAY_AMOUNT_TENDERED proc far
	;ENABLE NUMBER DISPLAY MODE
	MOV DS:Display_isNumber,1

	mov al,PACKAGE_ARR[1]
	mov ds:SegNum[0],AL

	mov al,PACKAGE_ARR[2]
	mov ds:SegNum[1],AL

	mov al,PACKAGE_ARR[3]
	mov ds:SegNum[2],AL

	mov al,PACKAGE_ARR[4]
	mov ds:SegNum[3],AL

	mov al,PACKAGE_ARR[5]
	mov ds:SegNum[4],AL

	mov al,PACKAGE_ARR[6]
	mov ds:SegNum[5],AL

	ret
DISPLAY_AMOUNT_TENDERED endp


DISPLAY_CURRENT_AMOUNT proc far

	MOV DS:Display_isNumber,1

	mov DX,DS:CURRENT_AMOUNT_H
	mov AX,DS:CURRENT_AMOUNT

	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[5],DL

;	CMP AX,0
;	JE END_DISPLAY_CURRENT_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[4],DL

;	CMP AX,0
;	JE END_DISPLAY_CURRENT_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[3],DL

;	CMP AX,0
;	JE END_DISPLAY_CURRENT_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[2],DL

;	CMP AX,0
;	JE END_DISPLAY_CURRENT_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[1],DL

;	CMP AX,0
;	JE END_DISPLAY_CURRENT_PRICE

	mov DX,0
	MOV BX,10
	DIV BX ;Q= AL, R=AH
	MOV DS:SegNum[0],DL

END_DISPLAY_CURRENT_PRICE:
	RET
DISPLAY_CURRENT_AMOUNT ENDP
;===================================================================
PROCESS_RECEIVED_DATA proc far
	mov BX,DATA_SEG
	mov ds,bx

	mov AL,ds:RECEIVE_ARR[0]

	CMP AL,0 ;START SUCCESS
	JE ACK_0

	CMP AL,1 ;ADD FAIL
	JE ACK_ERROR

	CMP AL,2 ;END SUCCESS
	JE ACK_2

	CMP AL,4 ;ADD SUCCESS
	JE ACK_4

	CMP AL,5 ;ADD FAIL
	JE ACK_ERROR

	CMP AL,6 ;ADD FAIL
	JE ACK_ERROR

	CMP AL,7 ;REMOVE SUCCESS
	JE ACK_7

	CMP AL,8 ;remove fail - barscode not exist
	JE ACK_ERROR

	CMP AL,9 ;remove fail - Q>added
	JE ACK_ERROR

	CMP AL,10 ;end fail - transation has no item
	JE ACK_ERROR

	cmp AL,11 ;end fail - transation has not started
	JE ACK_ERROR

	cmp AL,12 ;END FAIL – Amount Tendered < Total amount
	JE ACK_ERROR

	cmp AL,13
	je ACK_ERROR

	call far ptr DISPLAY_SHIFT_LEFT
	JMP FINISH_PROCESS_RECEIVED_DATA

ACK_0:
;RESET  QUANTITY,AMOUNT,PRICE
	call RESET_TRANSACTION
	JMP FINISH_PROCESS_RECEIVED_DATA

ACK_2:	;END SUCCESS
	mov AL,SOUND_YOUR_CHANGE
	call far ptr ENQUEUE_SOUND
	
	call DISPLAY_CHANGE
	CALL FAR PTR SAY_AMOUNT_DISPLAYED
	JMP FINISH_PROCESS_RECEIVED_DATA

ACK_4: ;ADD SUCCESS
	CALL GET_CURRENT_AMOUNT
	call ADD_TOTAL_AMOUNT
	call CHECK_MAX_CAPACITY

	JMP FINISH_PROCESS_RECEIVED_DATA

ACK_7: ;REMOVE SUCCESS
	CALL GET_CURRENT_AMOUNT
	MOV AX,DS:CURRENT_AMOUNT_H
	SUB DS:TOTAL_AMOUNT_H,AX

	MOV AX,DS:CURRENT_AMOUNT
	SUB DS:TOTAL_AMOUNT,AX

	jnc END_ACK_7
	dec DS:TOTAL_AMOUNT_H
	END_ACK_7:
;debug -- print carry
;	MOV AX,DS:TOTAL_AMOUNT_H
;	CALL FAR PTR PRINT_AL_DEBUG
;--------------------
	
	JMP FINISH_PROCESS_RECEIVED_DATA

ACK_ERROR:
	call DISPLAY_ERROR
	JMP FINISH_PROCESS_RECEIVED_DATA

FINISH_PROCESS_RECEIVED_DATA:
;print ACK end_byte
	;mov AL,24 ;pattern #24 = 'F'
	;call far ptr DISPLAY_SHIFT_LEFT
	ret
PROCESS_RECEIVED_DATA endp

DISPLAY_ERROR proc near 
	push AX

	;display "  E = "
	mov AL,PATTERN_SPACE
	call far ptr DISPLAY_SHIFT_LEFT
	mov AL,PATTERN_SPACE
	call far ptr DISPLAY_SHIFT_LEFT

	mov AL,PATTERN_E
	call far ptr DISPLAY_SHIFT_LEFT
	mov AL,PATTERN_EQU
	call far ptr DISPLAY_SHIFT_LEFT
	
	;say "Error"
	mov AL,SOUND_ERROR
	call far ptr ENQUEUE_SOUND

	pop AX

	cmp AL,10
	jae error_2digit
		call far ptr DISPLAY_SHIFT_LEFT
		call far ptr ENQUEUE_SOUND		
		jmp end_display_error

	error_2digit:
		sub AL,10
		mov BL,AL

		mov AL,1
		call far ptr DISPLAY_SHIFT_LEFT
		mov AL,BL
		call far ptr DISPLAY_SHIFT_LEFT

		MOV AH,1
		MOV AL,BL
		CALL FAR PTR SPEAK_2DIGITS

end_display_error:
	ret
DISPLAY_ERROR endp
;------------------------------------------------------------------
DISPLAY_CHANGE proc near

	mov DS:Display_isNumber,1

	mov al,RECEIVE_ARR[1]
	mov ds:SegNum[0],AL

	mov al,RECEIVE_ARR[2]
	mov ds:SegNum[1],AL

	mov al,RECEIVE_ARR[3]
	mov ds:SegNum[2],AL

	mov al,RECEIVE_ARR[4]
	mov ds:SegNum[3],AL

	mov al,RECEIVE_ARR[5]
	mov ds:SegNum[4],AL

	mov al,RECEIVE_ARR[6]
	mov ds:SegNum[5],AL

	ret
DISPLAY_CHANGE endp

RESET_TRANSACTION proc near
	mov ds:CURRENT_PRICE,0
	mov ds:CURRENT_QUANTITY,0
	mov ds:CURRENT_AMOUNT,0
	mov ds:TOTAL_AMOUNT,0

	mov ds:CURRENT_AMOUNT_H,0
	mov ds:TOTAL_AMOUNT_H,0

	mov ds:SegNum[0],0
	mov ds:SegNum[1],0
	mov ds:SegNum[2],0
	mov ds:SegNum[3],0
	mov ds:SegNum[4],0
	mov ds:SegNum[5],0
	ret
RESET_TRANSACTION endp


CHECK_MAX_CAPACITY proc near
;check whether Total_amount is within MAXIMUN amount for a transaction
	mov AX,DS:TOTAL_AMOUNT_H
	cmp Ax,0000Fh
	jb END_CHECK_CAPACITY 
;if execeed, end current transaction and ask cashier to start a new one
		mov AL,14 ;end trans
		call far ptr KEY_ENQUEUE
		call far ptr DISPLAY_SHIFT_LEFT 

		mov AL,11 ;enter
		call far ptr KEY_ENQUEUE
		call far ptr DISPLAY_SHIFT_LEFT 
		call far ptr SPEAKER_KEYPAD_INPUT
	
		inc ds:key_queue_ready
	END_CHECK_CAPACITY:
	ret
CHECK_MAX_CAPACITY endp
;------------------------------------------------------------------
ADD_TOTAL_AMOUNT proc near
	MOV AX,DS:CURRENT_AMOUNT
	ADD DS:TOTAL_AMOUNT,AX

	MOV AX,DS:CURRENT_AMOUNT_H
	ADC DS:TOTAL_AMOUNT_H,AX  ;ADD WITH CARRY

;debug -- print carry
;	MOV AX,DS:TOTAL_AMOUNT_H
;	CALL FAR PTR PRINT_AL_DEBUG
;--------------------

	RET
ADD_TOTAL_AMOUNT ENDP
;------------------------------------------------------------------
GET_CURRENT_AMOUNT proc near
;DISPLAY 'P='
	MOV AL,PATTERN_P
	call far ptr DISPLAY_SHIFT_LEFT

	MOV AL,PATTERN_EQU
	call far ptr DISPLAY_SHIFT_LEFT

;GET CURRENT_PRICE
	mov ds:CURRENT_PRICE,0

	XOR AX,AX
	MOV AL,DS:RECEIVE_ARR[1]
	call far ptr DISPLAY_SHIFT_LEFT
	MOV BX, 1000
	MUL BX
	add DS:CURRENT_PRICE,AX

	xor AX,AX
	MOV AL,DS:RECEIVE_ARR[2]
	call far ptr DISPLAY_SHIFT_LEFT
	MOV BX, 100
	MUL BX
	add DS:CURRENT_PRICE,AX

	xor AX,AX
	MOV AL,DS:RECEIVE_ARR[3]
	call far ptr DISPLAY_SHIFT_LEFT
	MOV BX, 10
	MUL BX
	ADD DS:CURRENT_PRICE,AX

	XOR AX,AX
	MOV AL,DS:RECEIVE_ARR[4]
	call far ptr DISPLAY_SHIFT_LEFT
	ADD DS:CURRENT_PRICE,AX

;SET NUMER DISPLAY MODE ON
	mov ds:Display_isNumber,1

;CURRENT_AMOUNT = CURRENT_PRICE X CURRENT_QUANTITY
	XOR DX,DX
	XOR BX,BX

	MOV AX,DS:CURRENT_PRICE
	MOV BL,DS:CURRENT_QUANTITY
	MUL BX
	MOV DS:CURRENT_AMOUNT,AX
	MOV DS:CURRENT_AMOUNT_H,DX

;;[DEBUG] print PRICE
;	CALL FAR PTR PRINTLN_DEBUG
;	MOV BX,DS:CURRENT_PRICE
;	mov AL,BH
;	call far ptr PRINT_2HEX
;	mov AL,BL
;	call far ptr PRINT_2HEX
;
;;[DEBUG] print CURRENT amount
;	CALL FAR PTR PRINTLN_DEBUG
;	mov BX,ds:CURRENT_AMOUNT
;	mov AL,BH
;	call far ptr PRINT_2HEX
;	mov AL,BL
;	call far ptr PRINT_2HEX
;
;	CALL FAR PTR PRINTLN_DEBUG	
	ret
GET_CURRENT_AMOUNT endp
;----------------------------------------------------
CODE_SEG	ENDS
END
